import React, { forwardRef, PureComponent } from 'react'
import {
  Collapse,
  DatePicker,
  Empty,
  Form,
  Input,
  message,
  Modal,
  Popconfirm,
  Radio,
  Select,
  Spin,
  Tooltip
} from 'antd'
import { DeleteOutlined, QuestionCircleOutlined, RightOutlined } from '@ant-design/icons'
import { connect } from '@umijs/max'
import { v4 } from 'uuid'
import moment from 'moment'
import { FIELD_TYPES } from '../const'
import { ProTable, ProTableOptions } from '@/components'
import { getDatabasesByDsType, getSourceDetail, getTopicAndColumns, previewKafkaData, saveSource } from '../../../api'
import styles from './index.less'

const { Panel } = Collapse
const { Option } = Select
const { TextArea } = Input

class Source extends PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      spreadSta: false,
      taskNode: {},
      allValues: {},
      SourceOptions: [{ name: 'Kafka', value: 0 }],
      dataSources: [],
      previewKafkaDatas: [],
      kafkaColumns: (index) => {
        const { sourceTableData } = this.state
        const key = sourceTableData[index].key
        return [
          {
            title: '字段',
            dataIndex: 'field',
            width: '35%',
            key: 'field',
            render: (text, record) => (
              <div>
                <Input
                  onChange={(e) => {
                    record.field = e.target.value
                    this.forceUpdate()
                  }}
                  onBlur={() => {
                    this.saveData()
                  }}
                  value={text}
                />
              </div>
            ),
          },
          {
            title: '类型',
            dataIndex: 'type',
            width: '35%',
            key: 'type',
            render: (text, record) => (
              <div>
                <Input
                  onChange={(e) => {
                    record.type = e.target.value
                    this.forceUpdate()
                  }}
                  onBlur={() => {
                    this.saveData()
                  }}
                  value={text}
                />
              </div>
            ),
          },
          {
            title: '操作',
            dataIndex: 'operation',
            width: '30%',
            key: 'operation',
            render: (text, record, i) => (
              <ProTableOptions>
                {[
                  <span onClick={() => {
                    this.deleteField(i, key)
                  }}
                  >
                    删除
                  </span>,
                ]}
              </ProTableOptions>
            ),
          },
        ]
      },
      partitionOffsetColumns: (index) => {
        const { sourceTableData } = this.state
        const key = sourceTableData[index].key
        return [
          {
            title: '分区编号',
            dataIndex: 'partition',
            width: '35%',
            key: 'partition',
            render: (text, record) => (
              <div>
                <Input
                  type="number"
                  onChange={(e) => {
                    record.partition = e.target.value
                    this.forceUpdate()
                  }}
                  onBlur={() => {
                    this.saveData()
                  }}
                  value={text}
                />
              </div>
            ),
          },
          {
            title: '偏移量',
            dataIndex: 'offset',
            width: '35%',
            key: 'offset',
            render: (text, record) => (
              <div>
                <Input
                  type="number"
                  onChange={(e) => {
                    record.offset = e.target.value
                    this.forceUpdate()
                  }}
                  onBlur={() => {
                    this.saveData()
                  }}
                  value={text}
                />
              </div>
            ),
          },
          {
            title: '操作',
            dataIndex: 'operation',
            width: '30%',
            key: 'operation',
            render: (text, record, i) => (
              <ProTableOptions>
                {[
                  <span onClick={() => {
                    this.deletePartition(1, key)
                  }}
                  >
                    删除
                  </span>,
                ]}
              </ProTableOptions>
            ),
          },
        ]
      },
      // 单一数据
      sourceTableData: [],
    }
    this.sourceForm = React.createRef()
    this.time = null
  }

  // 进入工作流页面，第一次点击工作流程目标，此时页面还未加载
  componentDidMount() {
    this.getDatabasesByDsType()
    this.setState(
      {
        taskNode: this.props?.taskNode,
      },
      () => {
        this.getSourceDetail()
      },
    )
  }

  UNSAFE_componentWillUpdate(nextProps) {
    if (nextProps.taskNode != this.props.taskNode) {
      // eslint-disable-next-line react/no-will-update-set-state
      this.setState(
        {
          taskNode: nextProps.taskNode,
        },
        () => {
          this.getSourceDetail()
        },
      )
    }
  }

  /**
   * 获取源表配置
   */
  getSourceDetail = () => {
    const { taskNode } = this.state
    const { nodeId } = taskNode || {}
    const params = {
      nodeId,
    }
    const sourceTableData = []
    getSourceDetail(params).then((res) => {
      if (res.status === 200) {
        const initDto = {}
        res.data.forEach((item, index) => {
          console.log(index)
          initDto[`sourceType[${index}]`] = item.dsType
          initDto[`dsId[${index}]`] = item.dsId
          initDto[`mappingTableName[${index}]`] = item.mappingTableName
          initDto[`offset[${index}]`] = item.kafkaSource
            ? item.kafkaSource.offset
            : null
          initDto[`timeType[${index}]`] = item.kafkaSource
            ? item.kafkaSource.timeType
            : null
          initDto[`delayMs[${index}]`] = item.kafkaSource
            ? item.kafkaSource.delayMs
            : null
          initDto[`timeField[${index}]`] = item.kafkaSource
            ? item.kafkaSource.timeField
            : null
          initDto[`topic[${index}]`] = item.kafkaSource
            ? item.kafkaSource.topic
            : null
          initDto[`startPointTime[${index}]`] = item.kafkaSource
            ? moment(item.kafkaSource.startPointTime)
            : null
          sourceTableData.push({
            name: '源表',
            key: v4(),
            topics: [initDto[`topic[${index}]`]],
            fieldList: item.fieldList,
            partitionOffsetList: item.kafkaSource
              ? item.kafkaSource.partitionOffsetList
              : [],
          })
          this.getTopicAndColumns(item.dsId, index)
        })
        this.setState(
          {
            // loaded: true,
            sourceTableData,
            allValues: initDto,
          },
          () => {
            this.sourceForm?.current?.setFieldsValue(initDto)
          },
        )
      }
    })
  }

  /**
   * 获取数据源
   */
  getDatabasesByDsType = () => {
    getDatabasesByDsType({
      dsType: 'Kafka',
    }).then((res) => {
      if (res.status === 200) {
        this.setState({
          dataSources: res.data,
        })
      }
    })
  }

  /**
   * 获取topic
   */
  getTopicAndColumns = (dsId, index) => {
    getTopicAndColumns({
      dsId,
    }).then((res) => {
      if (res.status === 200) {
        const { sourceTableData } = this.state
        sourceTableData[index].topics = res.data || []
        this.setState({
          sourceTableData: [...sourceTableData],
        })
      }
    })
  }

  // eslint-disable-next-line react/no-unused-class-component-methods
  toggleSource = (spreadStaParams = undefined) => {
    if (!this.state.spreadSta) {
      this.getSourceDetail()
    }
    this.setState((prevState) => ({
      spreadSta: spreadStaParams !== undefined ? spreadStaParams : !prevState.spreadSta,
    }))
  };

  /**
   * 添加源表
   */
  addSourceTable = () => {
    const key = v4()
    const { sourceTableData } = this.state
    const data = [...sourceTableData]
    data.push({
      name: '源表',
      key,
      topics: [],
      fieldList: [],
      partitionOffsetList: [],
    })
    this.setState({
      activeKeys: [key],
      sourceTableData: data,
    })
  }

  /**
   * 删除数据源
   * @param {number} index
   */
  deleteItem = (index) => {
    const { sourceTableData } = this.state
    const data = [...sourceTableData]
    data.splice(index, 1)

    this.setState(
      {
        sourceTableData: data,
      },
      () => {
        this.saveData()
      },
    )
  }

  /**
   * 添加字段
   */
  addField = (index) => {
    const { sourceTableData } = this.state
    const data = [...sourceTableData]
    data[index].fieldList.push({
      field: '',
      type: FIELD_TYPES[0],
    })

    this.setState({
      sourceTableData: data,
    })
  };

  addPartitionOffset = (index) => {
    const { sourceTableData } = this.state
    const data = [...sourceTableData]
    data[index].partitionOffsetList.push({
      partition: '',
      offset: '',
    })

    this.setState({
      sourceTableData: data,
    })
  };

  /**
   * 删除字段
   */
  deleteField = (index, key) => {
    const { sourceTableData } = this.state
    const data = [...sourceTableData]
    data.forEach((item) => {
      if (item.key === key) {
        item.fieldList.splice(index, 1)
      }
    })
    this.setState(
      {
        sourceTableData: data,
      },
      () => {
        this.saveData()
      },
    )
  }

  /**
   * 删除字段
   */
  deletePartition = (index, key) => {
    const { sourceTableData } = this.state
    const data = [...sourceTableData]
    data.forEach((item) => {
      if (item.key === key) {
        item.partitionOffsetList.splice(index, 1)
      }
    })
    this.setState(
      {
        sourceTableData: data,
      },
      () => {
        this.saveData()
      },
    )
  }

  /**
   * 数据表Kafka预览
   */
  previewKafkaData = (dsId, topic) => {
    this.setState({
      kafkaDataShow: true,
      confirmLoading: true,
    })
    previewKafkaData({
      dsId,
      topic,
    }).then((res) => {
      if (res.status === 200) {
        this.setState({
          previewKafkaDatas: res.data,
        })
      } else {
        message.error(res.msg)
      }
      this.setState({
        confirmLoading: false,
      })
    })
  }

  /**
   * 实时保存
   */
  saveData = () => {
    this.sourceForm?.current?.validateFields().then(fieldsValue => {
      if (!fieldsValue) return
      const result = this.state.sourceTableData.map((item, k) => {
        const dto = {}
        dto.fieldList = item.fieldList.map((field) => ({
          field: field.field,
          type: field.type,
        }))
        dto.dsId = fieldsValue[`dsId[${k}]`]
        dto.partitionOffsetList = item.partitionOffsetList.map(
          (partition) => ({
            partition: partition.partition,
            offset: partition.offset,
          }),
        )
        dto.mappingTableName = fieldsValue[`mappingTableName[${k}]`]
        dto.kafkaSource = {
          offset: fieldsValue[`offset[${k}]`],
          topic: fieldsValue[`topic[${k}]`],
          timeType: fieldsValue[`timeType[${k}]`],
          startPointTime: fieldsValue[`startPointTime[${k}]`]
            ? fieldsValue[`startPointTime[${k}]`].format(
              'YYYY-MM-DD HH:mm:ss',
            )
            : null,
          delayMs: fieldsValue[`delayMs[${k}]`]
            ? fieldsValue[`delayMs[${k}]`]
            : null,
          timeField: fieldsValue[`timeField[${k}]`]
            ? fieldsValue[`timeField[${k}]`]
            : null,
        }
        dto.timeType = fieldsValue[`timeType[${k}]`]
        dto.dsType = 'Kafka'
        return dto
      })
      saveSource({
        nodeId: this.state.taskNode?.nodeId,
        sources: result,
      }).then((res) => {
        if (res.status === 200) {
          this.props.getTaskDetail()
        }
      })
    })
  }

  valuesChange = (value, allValues) => {
    this.setState({
      allValues,
    }, () => {
      clearTimeout(this.time)
      this.time = setTimeout(() => {
        this.saveData()
      }, 1000)
    })
  }

  render() {
    const {
      spreadSta, sourceTableData, activeKeys, kafkaDataShow, allValues,
      kafkaColumns, partitionOffsetColumns, previewKafkaDatas, SourceOptions, dataSources,
    } = this.state
    return (
      <div className={`${styles.node_source} ${spreadSta ? styles.spread : ''}`}>
        <div className={styles.node_source_column}>
          源表
          <i
            className={`iconfont icon-addition_fill ${styles.addition_fill}`}
            onClick={() => {
              this.addSourceTable()
            }}
          />
        </div>
        <Form
          layout="vertical"
          ref={this.sourceForm}
          autoComplete="off"
          onValuesChange={this.valuesChange}
        >
          {
            sourceTableData && sourceTableData.length > 0 ? (
              <Collapse
                activeKey={activeKeys}
                onChange={(value) => {
                  this.setState({
                    activeKeys: value,
                  })
                }}
              >
                {sourceTableData.map((item, index) => (
                  <Panel
                    key={item.key}
                    header={
                      <div className={styles.real_time_task_panel_table_header}>
                        <span>
                          {item.name}
                          {index + 1}
                          {allValues[`mappingTableName[${index}]`]
                            ? `(${allValues[`mappingTableName[${index}]`]})`
                            : ''}
                        </span>
                        <span className={styles.delete_icon}>
                          <Popconfirm
                            placement="topLeft"
                            title="确认要删除这个源表吗？"
                            onConfirm={() => {
                              this.deleteItem(index)
                            }}
                            okText="确定"
                            cancelText="取消"
                          >
                            <DeleteOutlined
                              onClick={(e) => {
                                e.stopPropagation()
                                e.preventDefault()
                              }}
                            />
                          </Popconfirm>
                          <RightOutlined />
                        </span>
                      </div>
                    }
                    forceRender
                    showArrow={false}
                  >
                    <Form.Item
                      name={`sourceType[${index}]`}
                      rules={[
                        { required: true, message: '请选择类型' },
                      ]}
                      label="类型"
                    >
                      <Select
                        autoComplete="off"
                        placeholder="请选择类型"
                      >
                        {SourceOptions.map((o) => (
                          <Option
                            label={o.name}
                            key={o.value}
                            value={o.value}
                          >
                            {o.name}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                    <Form.Item
                      name={`dsId[${index}]`}
                      rules={[
                        { required: true, message: '请选择数据源' },
                      ]}
                      label="数据源"
                    >
                      <Select
                        showSearch
                        autoComplete="off"
                        placeholder="请选择数据源"
                        onChange={(val) => {
                          this.getTopicAndColumns(val, index)
                          this.sourceForm?.current?.setFieldsValue({
                            [`topic[${index}]`]: undefined,
                          })
                        }}
                        filterOption={(input, option) => option.props.title
                          .toLowerCase()
                          .indexOf(input.toLowerCase()) >= 0}
                      >
                        {dataSources.map((o) => (
                          <Option
                            key={o.dsId}
                            value={o.dsId}
                            title={`${o.dsName}（${o.dsType}）`}
                          >
                            <div className="source-name">
                              {`${o.dsName}（${o.dsType}）`}
                            </div>
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                    <Form.Item
                      className={styles.real_time_form_item_full}
                      name={`topic[${index}]`}
                      rules={[
                        { required: true, message: '请选择Topic' },
                      ]}
                      label={
                        <span style={{ width: '100%' }}>
                          <span>Topic</span>
                          <span
                            className={styles.real_time_form_item_full_right}
                            onClick={() => {
                              this.previewKafkaData(
                                allValues[`dsId[${index}]`],
                                allValues[`topic[${index}]`],
                              )
                            }}
                          >
                            数据预览
                          </span>
                        </span>
                      }
                    >
                      <Select
                        showSearch
                        autoComplete="off"
                        placeholder="请选择Topic"
                        filterOption={(inputValue, option) => (
                          option.props.children
                            .toUpperCase()
                            .indexOf(inputValue.toUpperCase()) !== -1
                        )}
                      >
                        {(sourceTableData[index].topics || []).map(
                          (v) => (
                            <Option label={v} key={v} value={v}>
                              {v}
                            </Option>
                          ),
                        )}
                      </Select>
                    </Form.Item>
                    <Form.Item
                      label={
                        <span>
                          映射表&nbsp;
                          <Tooltip
                            title={
                              <div>
                                <p>
                                  该表是kafka中的topic映射而成，可以以SQL的方式使用它。
                                </p>
                              </div>
                            }
                          >
                            <QuestionCircleOutlined />
                          </Tooltip>
                        </span>
                      }
                      name={`mappingTableName[${index}]`}
                      rules={[
                        { required: true, message: '请输入映射表' },
                      ]}
                    >
                      <Input
                        autoComplete="off"
                        placeholder="请输入映射表"
                      />
                    </Form.Item>
                    <Form.Item
                      className={styles.real_time_form_item_full}
                      label={
                        <span style={{ width: '100%' }}>
                          <span>字段</span>
                          <span
                            className={styles.real_time_form_item_full_right}
                            onClick={() => {
                              this.addField(index)
                            }}
                          >
                            添加
                          </span>
                        </span>
                      }
                    >
                      <ProTable
                        pagination={false}
                        columns={kafkaColumns(index)}
                        dataSource={item.fieldList}
                      />
                    </Form.Item>
                    <Form.Item
                      label={
                        <span>
                          Offset&nbsp;
                          <Tooltip
                            title={
                              <div>
                                <p>latest：从Kafka Topic内最新的数据开始消费</p>
                                <p>
                                  earliest：从Kafka Topic内最老的数据开始消费
                                </p>
                              </div>
                            }
                          >
                            <QuestionCircleOutlined />
                          </Tooltip>
                        </span>
                      }
                      name={`offset[${index}]`}
                      rules={[
                        { required: true, message: '请选择Offset' },
                      ]}
                    >
                      <Radio.Group>
                        <Radio value={0}>Latest</Radio>
                        <Radio value={1}>Earliest</Radio>
                        <Radio value={2}>Time</Radio>
                        <Radio value={3}>GroupOffsets</Radio>
                        <Radio value={4}>SpecificOffsets</Radio>
                      </Radio.Group>
                    </Form.Item>
                    {allValues[`offset[${index}]`] === 2 ? (
                      <Form.Item
                        name={`startPointTime[${index}]`}
                        rules={[
                          { required: true, message: '请选择时间' },
                        ]}
                        label="启动时间"
                      >
                        <DatePicker
                          showTime
                          placeholder="请选择时间"
                        />
                      </Form.Item>
                    ) : null}
                    {allValues[`offset[${index}]`] === 4 ? (
                      <Form.Item
                        className={styles.real_time_form_item_full}
                        label={
                          <span style={{ width: '100%' }}>
                            <span>分区</span>
                            <span
                              className={styles.real_time_form_item_full_right}
                              onClick={() => {
                                this.addPartitionOffset(index)
                              }}
                            >
                              添加
                            </span>
                          </span>
                        }
                      >
                        <ProTable
                          pagination={false}
                          columns={partitionOffsetColumns(index)}
                          dataSource={item.partitionOffsetList}
                        />
                      </Form.Item>
                    ) : null}
                    <Form.Item
                      label={
                        <span>
                          时间特征&nbsp;
                          <Tooltip
                            title={
                              <div>
                                <p>ProcTime：按照Flink的处理时间处理</p>
                                <p>
                                  EventTime：按照流式数据本身包含的业务时间戳处理
                                </p>
                              </div>
                            }
                          >
                            <QuestionCircleOutlined />
                          </Tooltip>
                        </span>
                      }
                      name={`timeType[${index}]`}
                      rules={[
                        { required: true, message: '请选择时间特征' },
                      ]}
                    >
                      <Radio.Group>
                        <Radio value={0}>ProcTime</Radio>
                        <Radio value={1}>EventTime</Radio>
                      </Radio.Group>
                    </Form.Item>
                    {allValues[`timeType[${index}]`] === 1 ? (
                      <Form.Item
                        name={`timeField[${index}]`}
                        rules={[
                          { required: true, message: '请选择时间列' },
                        ]}
                        label="时间列"
                      >
                        <Select
                          autoComplete="off"
                          placeholder="请选择时间列"
                        >
                          {item.fieldList.map((o) => (
                            <Option
                              label={o.field}
                              key={o.field}
                              value={o.field}
                            >
                              {o.field}
                            </Option>
                          ))}
                        </Select>
                      </Form.Item>
                    ) : null}
                    {allValues[`timeType[${index}]`] === 1 ? (
                      <Form.Item
                        name={`delayMs[${index}]`}
                        rules={[
                          { required: true, message: '请输入最大延迟时间' },
                        ]}
                        label="最大延迟时间"
                      >
                        <Input
                          suffix="ms"
                          autoComplete="off"
                          placeholder="请输入最大延迟时间"
                        />
                      </Form.Item>
                    ) : null}
                  </Panel>
                ))}
              </Collapse>
            ) : (
              <Empty
                className={styles.real_time_task_panel_empty}
                description={
                  <span>
                    暂无源表，请{' '}
                    <span
                      className={styles.empty_add}
                      onClick={() => {
                        this.addSourceTable()
                      }}
                    >
                      添加
                    </span>
                  </span>
                }
              />
            )
          }
        </Form>
        <Modal
          destroyOnClose
          title="数据预览"
          visible={kafkaDataShow}
          onCancel={() => {
            this.setState({
              kafkaDataShow: false,
            })
          }}
          footer={null}
        >
          <Spin spinning={this.state.confirmLoading}>
            <div className={styles.preview_data_box}>
              {previewKafkaDatas && previewKafkaDatas.length ? (
                <Collapse>
                  {previewKafkaDatas
                    && previewKafkaDatas.map((item, key) => (
                      <Panel
                        header={<p className={styles.preview_data_box_p}>{item}</p>}
                        key={key}
                      >
                        <TextArea
                          value={item}
                          autoSize={{ minRows: 3, maxRows: 5 }}
                        />
                      </Panel>
                    ))}
                </Collapse>
              ) : (
                <Empty
                  description={<span>暂无数据</span>}
                />
              )}
            </div>
          </Spin>
        </Modal>
      </div>
    )
  }
}

class WrappedComponentRef extends PureComponent {
  render() {
    const { forwardedRef, ...rest } = this.props
    return (
      <Source ref={forwardedRef} {...rest} />
    )
  }
}

const IComponent = connect(({ realTimeScriptDev }) => ({ ...realTimeScriptDev }))(WrappedComponentRef)

export default forwardRef((props, ref) => <IComponent {...props} forwardedRef={ref} />)
